-
Notifications
You must be signed in to change notification settings - Fork 86
fix: force serverless target #343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Fixes #204 :D |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just need to update the tests :) plus few comments
helpers/hasCorrectNextConfig.js
Outdated
delete require.cache[require.resolve('next/dist/next-server/server/config')] | ||
|
||
// Clear memoized cache | ||
getNextConfig.clear() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we have to clear here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function is memoized, so it will return the old value if we don't clear it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This works.
In the long run, we probably should consider removing memoization on getNextConfig()
and passing its return value around function calls instead.
index.js
Outdated
} | ||
} | ||
// Populates the correct config if needed | ||
await doesNotNeedPlugin({ netlifyConfig, packageJson, failBuild }) | ||
|
||
// Because we memoize nextConfig, we need to do this after the write file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can prob remove this comment now i think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
double ping on this one?
// Because we memoize nextConfig, we need to do this after the write file |
helpers/hasCorrectNextConfig.js
Outdated
@@ -12,9 +11,27 @@ const hasCorrectNextConfig = async ({ nextConfigPath, failBuild }) => { | |||
const isValidTarget = acceptableTargets.includes(target) | |||
if (!isValidTarget) { | |||
console.log( | |||
`Your next.config.js must set the "target" property to one of: ${acceptableTargets.join(', ')}. Update the | |||
target property to allow this plugin to run.`, | |||
`The "target" config property must be one of "${acceptableTargets.join('", "')}". Setting it to "serverless".`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Settingit to serverless" might imply to some that we're actually mutating/updating/changing their config file (which i don't think we're doing? 🤔 ). maybe "forcing the build to use target serverless" or something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point
@lindsaylevine what do you think about disabling those tests for now until we can work out a better way of checking if it's run? |
@ascorbic we can def remove the next export one. how about setting an env variable at the end of each step and checking that? i dont see a problem w that 🤔 |
helpers/hasCorrectNextConfig.js
Outdated
// https://github.com/vercel/next.js/blob/canary/packages/next/telemetry/ci-info.ts | ||
|
||
delete require.cache[require.resolve('next/dist/telemetry/ci-info')] | ||
delete require.cache[require.resolve('next/dist/next-server/server/config')] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Considering next
is performing some logic at require()
-time, this approach makes sense.
The only alternative I can think of would be to call getNextConfig()
in a separate process. However, this would add some significant complexity. Also, this would JSON-serialize the Next.js configuration, which would not work if the config includes non-JSON values (can it?), unless we use serialization: 'advanced'
but that option is not available in Node 10.
Two potential problems we might have in the future though are:
- I am unsure whether this would work with ES modules since the current Node.js implementation does not allow removing cached URLs (it allows passing query parameters as cache key, but this would not work here), so this might require mixing CommonJS
require()
and ES modulesimport
in order to keep usingrequire.cache
. - This relies on
next
internal file structure. The cache deletion would be a noop if they choose to rename those files. Some things we could do to fix this:- Run some automated tests confirming those files exist with the latest version of
next
delete
all thenext
entries inrequire.cache
instead of those specific files
- Run some automated tests confirming those files exist with the latest version of
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately we're already relying on the internal layout as we're using unpublished exports to get the config in the first place
yes that's definitely coming up!!! @Mickael
…On Tue, May 25, 2021 at 9:14 AM ehmicky ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In helpers/hasCorrectNextConfig.js
<#343 (comment)>
:
> + /* eslint-disable fp/no-delete, node/no-unpublished-require */
+
+ // We emulate Vercel so that we can set target to serverless if needed
+ process.env.NOW_BUILDER = true
+ // If no valid target is set, we use an internal Next env var to force it
+ process.env.NEXT_PRIVATE_TARGET = 'serverless'
+
+ // 🐉 We need Next to recalculate "isZeitNow" var so we can set the target, but it's
+ // set as an import side effect so we need to clear the require cache first. 🐲
+ // https://github.com/vercel/next.js/blob/canary/packages/next/telemetry/ci-info.ts
+
+ delete require.cache[require.resolve('next/dist/telemetry/ci-info')]
+ delete require.cache[require.resolve('next/dist/next-server/server/config')]
+
+ // Clear memoized cache
+ getNextConfig.clear()
This works.
In the long run, we probably should consider removing memoization on
getNextConfig() and passing its return value around function calls
instead.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#343 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ANVRQIWQHNFTCFCZQ2TKCKDTPOPFBANCNFSM45M7X4CQ>
.
|
helpers/hasCorrectNextConfig.js
Outdated
// We emulate Vercel so that we can set target to serverless if needed | ||
process.env.NOW_BUILDER = true | ||
// If no valid target is set, we use an internal Next env var to force it | ||
process.env.NEXT_PRIVATE_TARGET = 'serverless' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe some automated tests might be using the same process, i.e. running one test would change process.env
for other tests. We could probably fix this by either:
- Spawning those tests in different processes
- Loading
next
right away so it uses those environment variables, then deletingprocess.env.NOW_BUILDER
andprocess.env.NEXT_PRIVATE_TARGET
(or restoring them to their original value).
I would personally suggest either:
|
I worked it out. I extracted the target updating code into a different funciton, so it wasn't combined with the checks which I then run before. In the tests I check whether |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏 💯
/* eslint-enable fp/no-delete, node/no-unpublished-require */ | ||
} | ||
|
||
module.exports = verifyBuildTarget |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
love this 🙏
console.log( | ||
`The "target" config property must be one of "${acceptableTargets.join( | ||
'", "', | ||
)}". Building with "serverless" target.`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NICE
index.js
Outdated
} | ||
} | ||
// Populates the correct config if needed | ||
await doesNotNeedPlugin({ netlifyConfig, packageJson, failBuild }) | ||
|
||
// Because we memoize nextConfig, we need to do this after the write file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
double ping on this one?
// Because we memoize nextConfig, we need to do this after the write file |
delete require.cache[require.resolve('next/dist/telemetry/ci-info')] | ||
delete require.cache[require.resolve('next/dist/next-server/server/config')] | ||
|
||
getNextConfig.clear() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:O omg. we couldve done this the whole time...................
test/index.js
Outdated
@@ -89,14 +85,15 @@ describe('preBuild()', () => { | |||
}) | |||
|
|||
test('run plugin if the app has next export in an unused script', async () => { | |||
process.env.hi = 'ok' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hi
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hah. oops
test/index.js
Outdated
|
||
expect(await pathExists('next.config.js')).toBeTruthy() | ||
expect(process.env.NEXT_PRIVATE_TARGET).toBe('serverless') | ||
// expect(await pathExists('next.config.js')).toBeTruthy() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// expect(await pathExists('next.config.js')).toBeTruthy() |
@@ -133,7 +130,7 @@ describe('preBuild()', () => { | |||
utils, | |||
}) | |||
|
|||
expect(await pathExists('next.config.js')).toBeFalsy() | |||
expect(process.env.NEXT_PRIVATE_TARGET).toBeUndefined() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
brilliant
Co-authored-by: Michal Piechowiak <[email protected]>
Uses an env var to emulate Vercel, then another to force the target to serverless if it's not set as
serverless
orexperimental-serverless-trace